/**
 * @file Calendar.js
 * @description 
 * Class to create calendar
 *
 * $id:v1.0.0, 2009-03-02 14:03, baboo<istxwang@gmail.com>$
 */

(function ($) {

$.Calendar = $({
    __getDefaultSets : function () {
        return {
            classNames : {
                'table' : 'cal_table',
                'thead' : 'cal_thead',
                'tbody' : 'cal_tbody',
                'tfoot' : 'cal_tfoot',
                'prevYearBtn' : 'cal_prev_year_btn',
                'nextYearBtn' : 'cal_next_year_btn',
                'prevMonBtn' : 'cal_prev_mon_btn',
                'nextMonBtn' : 'cal_next_mon_btn',
                'year' : 'cal_year',
                'month' : 'cal_month',
                'customCaption' : 'cal_custom',
                'weekday' : 'cal_weekday',
                'today' : 'cal_today',
                'before' : 'cal_before',
                'after' : 'cal_after',
                'selected' : 'cal_selected'
            },
            lang : 'cn',
            show : true
        };
    },

    __init : function (cntId, sets) {
        this.sets = $.extend(this.__getDefaultSets(), sets || {});
        this.lang = $.Calendar.languages[this.sets.lang];
        this.date = new Date();
        this.today = new Date();
        this.selected = null;
        this.__create(document.getElementById(cntId));
        this.__buildDays();
        this.sets.show && this.show();
    },

    __create : function (cnt) {
        var mk = $.Builder.node, cns = this.sets.classNames, lang = this.lang;
        var tb = mk('table');
        tb.className = cns.table;
        var th = tb.createTHead();
        th.className = cns.thead;
        tb.createCaption().innerHTML =  
            ['<a class="${prevYearStyle}" href="javascript:void(0)" title="${prevYearText}">&lt;</a>',
            '<b class="${yearStyle}"></b>',
            '<a class="${nextYearStyle}" href="javascript:void(0)" title="${nextYearText}">&gt;</a>',
            '<a class="${prevMonStyle}" href="javascript:void(0)" title="${prevMonText}">&lt;</a>',
            '<b class="${monthStyle}"></b>',
            '<a class="${nextMonStyle}" href="javascript:void(0)" title="${nextMonText}">&gt;</a>',
            '<i class="${customCaptionStyle}">${customCaption}</i>'
            ].join('').process({
                prevYearStyle : cns.prevYearBtn,
                yearStyle : cns.year,
                nextYearStyle : cns.nextYearBtn,
                prevMonStyle : cns.prevMonBtn,
                monthStyle : cns.month,
                nextMonStyle : cns.nextMonBtn,
                customCaptionStyle : cns.customCaption,
                prevYearText: lang.prevYear,
                nextYearText : lang.nextYear,
                prevMonText : lang.prevMonth,
                nextMonText : lang.nextMonth,
                customCaption : this.sets.customCaption || ''
            });
        this.__createRow(th, lang.week.shortnames, function(i, d) {
            return '<b class="{0} {1}">{2}</b>'.format(cns.weekday, cns.weekday + 'i', d);
        });
        var tbody = mk('tbody');
        tbody.className = cns.tbody;
        tb.appendChild(tbody);
        for (var i = 0; i < 6; i++) this.__createRow(tbody, []);
        tb.style.display = 'none';
        cnt.appendChild(tb);                

        this.dayCells = tbody.getElementsByTagName('td');
        this.$table = $(tb);
        this.$year = this.$table.find('*.' + cns.year);
        this.$month = this.$table.find('*.' + cns.month);
        this.$table.find('*.' + cns.prevMonBtn).click(this.prevMonth.bind(this));
        this.$table.find('*.' + cns.nextMonBtn).click(this.nextMonth.bind(this));
        this.$table.find('*.' + cns.prevYearBtn).click(this.prevYear.bind(this));
        this.$table.find('*.' + cns.nextYearBtn).click(this.nextYear.bind(this));
        if (this.sets.customCaption && this.sets.onCustomCaptionClick) {
            this.$table.find('*.' + cns.customCaption).click(this.sets.onCustomCaptionClick);
        }
        $.bind(tbody, 'click', this.__clickHandler.bind(this));
    },

    __createRow : function (p, celldatas, oncreate) {
        var r = p.insertRow(-1);
        if ($.isArray(celldatas)) {
            for (var i = 0; i < 7; i ++) {
                var cell = r.insertCell(-1);
                var data = celldatas[i] || '';
                cell.innerHTML = oncreate ? oncreate(i, data) : data;
            }
        } else {
            var cell = r.insertCell(-1);
            cell.colSpan = 7;
            cell.innerHTML = oncreate ? oncreate(0, celldatas) : celldatas;
        }
    },

    show : function () {
        this.$table.show();
    },

    hide : function () { this.$table.hide(); },

    prevMonth : function () {
        var d = this.date, m = d.getMonth();
        if (m > 0) {
            d.setMonth(m - 1);
            this.__buildDays();
        }
    },

    nextMonth : function () {
        var d = this.date, m = d.getMonth();
        if (m < 11) {
            d.setMonth(m + 1);
            this.__buildDays();
        }
    },

    prevYear : function () {
        var d = this.date, y = d.getFullYear();
        if (y > 0) {
            d.setFullYear(y - 1);
            this.__buildDays();
        }
    },

    nextYear : function () {
        var d = this.date, y = d.getFullYear();
        d.setFullYear(y + 1);
        this.__buildDays();
    },

    __clickHandler : function (event) {
        var d = this.date;
        var td = $(event.target).find(':up(td)', true).get(0);
        if (td) {
            var date = td.innerHTML.stripTags();
            date = parseInt((date.match(/\d+/) || [0])[0], 10);
            if (date) {
                var r = new Date(d.getTime());
                r.setDate(date);
                this.selected = r;
                if (this.$selected) this.$selected.className('-', this.sets.classNames.selected);
                this.$selected = $('a', td);
                this.$selected.className('+', this.sets.classNames.selected);
                if (this.sets.onChoose) {
                    this.sets.onChoose(r);
                }
            }
        }
    },

    setChoosed : function (d) {
        this.date.setFullYear(d.getFullYear());
        this.date.setMonth(d.getMonth());
        this.selected = d;
        this.__buildDays();
    },

    __buildDays : function () {
        var d = this.date, m = d.getMonth(), y = d.getFullYear(), cells = this.dayCells, cns = this.sets.classNames;
        this.$year.html(y);
        this.$month.html(m + 1);
        this.$selected = null;
        d.setDate(1);

        var days = $.Calendar.monthDays[d.isLeap() ? 'leap' : 'noLeap'][m],
        start = d.getDay(), end = start + days - 1, cell, style, date,
        todayVal = this.today.getFullYear() * 10000 + this.today.getMonth() * 100 + this.today.getDate(), tempVal = y * 10000 + m * 100, selectedVal = 0, selectedIndex = -1;
        if (this.selected) {
            selectedVal = this.selected.getFullYear() * 10000 + this.selected.getMonth() * 100 + this.selected.getDate();
        }
        for (var i = 0; i < cells.length; i++) {
            cell = cells[i];
            if (i < start || i > end) {
                cell.innerHTML = '';
            } else {
                date = i - start + 1;
                style = [];
                if (todayVal == tempVal + date) {
                    style.push(cns.today);
                } else if (todayVal > tempVal + date) {
                    style.push(cns.before);
                } else {
                    style.push(cns.after);
                }
                if (selectedVal == tempVal + date) {
                    style.push(cns.selected);
                    selectedIndex = i;
                }
                cell.innerHTML = '<a href="javascript:void(0)" class="{1}">{0}</a>'.format(date, style.join(' '));
            }
        }
        if (selectedIndex >= 0) {
            this.$selected = $('a', cells[i]);
        }
    }
});

if (!Date.prototype.isLeap) {
    Date.prototype.isLeap = function () {
        var y = this.getFullYear(); 
        if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) { return true; } 
        return false; 
    };
}

$.Calendar.monthDays = {
    'leap' :  [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
    'noLeap' : [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
};

$.Calendar.languages = {};

$.Calendar.languages.cn = {
	week : {
	    shortnames : ['日', '一', '二', '三', '四', '五', '六']
	},
	prevYear : '上一年',
	nextYear : '下一年',
	prevMonth : '上个月',
	nextMonth : '下个月'
};
	
})($imple);





